home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / Pascal / Source□ / Talk Source / TCP Libraries / TCPConnections.unit next >
Encoding:
Text File  |  1992-04-20  |  16.8 KB  |  611 lines  |  [TEXT/PJMM]

  1. unit TCPConnections;
  2.  
  3. { This program was written by Peter N Lewis, Mar 1992 in THINK Pascal 4.0.1 }
  4.  
  5. interface
  6.  
  7.     uses
  8.         TCPStuff;
  9.  
  10.     const  { Tuning parameters }
  11.         max_connections = 20;
  12.         tooManyConnections = -23099;
  13.         TO_FindAddress = 40 * 60;
  14.         TO_FindName = 40 * 60;
  15.         TO_ActiveOpen = 20 * 60;
  16.         TO_Closing = 20 * 60;
  17.         TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  18.  
  19.     const
  20.         any_connection = 0;    { Pass to GetConnectionEvent }
  21.         no_connection = -1;    { Guaranteed invalid connection }
  22.  
  23.     type
  24.         connectionIndex = longInt;
  25.         connectionEvent = (C_NoEvent, C_Found, C_SearchFailed, C_NameFound, C_NameSearchFailed,{}
  26.             C_Established, C_FailedToOpen, C_Closing, C_Closed, C_CharsAvailable, C_HeartBeat);
  27.         connectionEventRecord = record
  28.                 event: connectionEvent;
  29.                 connection: connectionIndex;
  30.                 tcpc: TCPConnectionPtr;
  31.                 dataptr: ptr;
  32.                 value: longInt;
  33.                 timedout: boolean;
  34.             end;
  35.  
  36.     function InitConnections (hostFile: str255): OSErr;
  37.     procedure CloseConnections;
  38.     procedure TerminateConnections;
  39.     function CanQuit: boolean;
  40. { After Terminate, keep calling GetConnectionEvent(any_connection,cer) until CanQuit is true, then Finish }
  41.     procedure FinishConnections;
  42.     procedure FinishEverything;  { Or just call FinishEverything }
  43.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  44.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  45.     procedure FindString (hostIP: longInt; var s: str255);
  46.     function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  47.     function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  48.     procedure CloseConnection (cp: connectionIndex);
  49.     procedure AbortConnection (cp: connectionIndex); { Violently close connection }
  50.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  51. { Pass any_connection for any event, otherwise cp specifies the event }
  52.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  53.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  54.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  55.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  56.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  57.     procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks, 0 disables heartbeat }
  58.  
  59. implementation
  60.  
  61.     const
  62.         TCPCMagic = 'TCPC';
  63.         TCPCBadMagic = 'badc';
  64.  
  65.     type
  66.         myHostInfo = record
  67.                 hi: hostInfo;
  68.                 done: signedByte;
  69.             end;
  70.         myHostInfoPtr = ^myHostInfo;
  71.         statusType = (CS_None, CS_Searching, CS_NameSearching, CS_Opening, CS_Established, CS_Closing);
  72.         connectionRecord = record
  73.                 magic: OSType;
  74.                 conmagic: longInt;
  75.                 tcpc: TCPConnectionPtr;
  76.                 status: statusType;
  77.                 cacheFaultReturnP: myHostInfoPtr;
  78.                 closedone: boolean;
  79.                 timeout: longInt;
  80.                 dataptr: ptr;
  81.                 heartbeat: longInt; { Time for next heartbeat }
  82.                 period: longInt; { Ticks per heartbeat }
  83.             end;
  84.  
  85.     var
  86.         connections: array[1..max_connections] of connectionRecord;
  87.         connectionItem: connectionIndex;
  88.         dnrptr: ptr;
  89.         connectionmagic: longInt;
  90.  
  91.     function ValidConnection (var cp: connectionIndex): boolean;
  92.         var
  93.             ocp: longInt;
  94.             vc: boolean;
  95.     begin
  96.         vc := false;
  97.         ocp := cp;
  98.         cp := cp mod (max_connections + 1);
  99.         if cp > 0 then
  100.             if connections[cp].magic = TCPCMagic then
  101.                 if connections[cp].conmagic = ocp then
  102.                     vc := true;
  103.         if not vc then
  104.             DebugStr('Invalid Connection');
  105.         ValidConnection := vc;
  106.     end;
  107.  
  108.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  109.     begin
  110.         if ValidConnection(cp) then
  111.             connections[cp].dataptr := dataptr;
  112.     end;
  113.  
  114.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  115.     begin
  116.         if ValidConnection(cp) then
  117.             dataptr := connections[cp].dataptr
  118.         else
  119.             dataptr := nil;
  120.     end;
  121.  
  122.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  123.     begin
  124.         if ValidConnection(cp) then
  125.             connections[cp].timeout := timeout;
  126.     end;
  127.  
  128.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  129.     begin
  130.         if ValidConnection(cp) then
  131.             timeout := connections[cp].timeout
  132.         else
  133.             timeout := -1;
  134.     end;
  135.  
  136.     procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks }
  137.     begin
  138.         if ValidConnection(cp) then begin
  139.             if (n < 1) or (n = maxLongInt) then begin
  140.                 connections[cp].period := maxLongInt;
  141.                 connections[cp].heartbeat := maxLongInt;
  142.             end
  143.             else begin
  144.                 connections[cp].period := n;
  145.                 connections[cp].heartbeat := TickCount + n;
  146.             end;
  147.         end;
  148.     end;
  149.  
  150.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  151.     begin
  152.         if ValidConnection(cp) then
  153.             tcpc := connections[cp].tcpc
  154.         else
  155.             tcpc := nil;
  156.     end;
  157.  
  158.     function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  159.     begin
  160.         if con = nil then
  161.             MyTCPState := T_Closed
  162.         else
  163.             MyTCPState := TCPState(con);
  164.     end;
  165.  
  166. {$S Init}
  167.     function InitConnections (hostFile: str255): OSErr;
  168.         var
  169.             oe, ooe: OSErr;
  170.             i: connectionIndex;
  171.     begin
  172.         for i := 1 to max_connections do
  173.             connections[i].magic := TCPCBadMagic;
  174.         connectionmagic := 0;
  175.         connectionItem := 1;
  176.         oe := TCPInit;
  177.         if oe = noErr then begin
  178.             oe := TCPOpenResolver(hostFile, dnrptr);
  179.             if oe <> noErr then
  180.                 TCPFinish;
  181.         end;
  182.         InitConnections := oe;
  183.     end;
  184.  
  185. {$S Term}
  186.     procedure TerminateConnections;
  187.         var
  188.             i: connectionIndex;
  189.             oe: OSErr;
  190.     begin
  191.         for i := 1 to max_connections do
  192.             with connections[i] do
  193.                 if magic = TCPCMagic then
  194.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  195.                         if TCPState(tcpc) <> T_Closed then
  196.                             oe := TCPAbort(tcpc);
  197.     end;
  198.  
  199. {$S Term}
  200.     procedure CloseConnections;
  201.         var
  202.             i: connectionIndex;
  203.             oe: OSErr;
  204.     begin
  205.         for i := 1 to max_connections do
  206.             with connections[i] do
  207.                 if magic = TCPCMagic then
  208.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  209.                         if TCPState(tcpc) <> T_Closed then
  210.                             oe := TCPClose(tcpc, nil);
  211.     end;
  212.  
  213. {$S Term}
  214.     function CanQuit: boolean;
  215.         var
  216.             i: connectionIndex;
  217.     begin
  218.         CanQuit := true;
  219.         for i := 1 to max_connections do
  220.             if connections[i].magic = TCPCMagic then
  221.                 CanQuit := false;
  222.     end;
  223.  
  224. {$S Term}
  225.     procedure FinishConnections;
  226.     begin
  227.         TCPCloseResolver(dnrptr);
  228.         TCPFinish;
  229.     end;
  230.  
  231. {$S Term}
  232.     procedure FinishEverything;
  233.         var
  234.             cer: connectionEventRecord;
  235.             dummy: boolean;
  236.             er: eventrecord;
  237.             oe: OSErr;
  238.     begin
  239.         TerminateConnections;
  240.         while not CanQuit do begin
  241.             if GetConnectionEvent(any_connection, cer) then begin
  242.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  243.             end
  244.             else
  245.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  246.         end;
  247.         FinishConnections;
  248.     end;
  249.  
  250. {$S}
  251.     function CreateConnection (var cp: connectionIndex; dp: ptr): OSErr;
  252.     begin
  253.         connectionmagic := connectionmagic + max_connections + 1;
  254.         cp := 1;
  255.         while (connections[cp].magic = TCPCMagic) and (cp < max_connections) do
  256.             cp := cp + 1;
  257.         with connections[cp] do begin
  258.             if magic = TCPCMagic then
  259.                 CreateConnection := tooManyConnections
  260.             else begin
  261.                 magic := TCPCMagic;
  262.                 conmagic := cp + connectionmagic;
  263.                 closedone := false;
  264.                 tcpc := nil;
  265.                 status := CS_None;
  266.                 cacheFaultReturnP := nil;
  267.                 timeout := maxlongInt;
  268.                 dataptr := dp;
  269.                 period := maxLongInt;
  270.                 heartbeat := maxLongInt;
  271.                 CreateConnection := noErr;
  272.                 cp := cp + connectionmagic;
  273.             end;
  274.         end;
  275.     end;
  276.  
  277.     procedure DestroyConnection (var cp: connectionIndex);
  278.     begin
  279.         if not ValidConnection(cp) then
  280.             DebugStr('Destroy Connection failed')
  281.         else
  282.             connections[cp].magic := TCPCBadMagic;
  283.         cp := -1;
  284.     end;
  285.  
  286.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  287.         var
  288.             oe: OSErr;
  289.             cpi: connectionIndex;
  290.     begin
  291.         oe := CreateConnection(cp, dataptr);
  292.         if oe = noErr then begin
  293.             cpi := cp;
  294.             if ValidConnection(cpi) then begin
  295.                 with connections[cpi] do begin
  296.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  297.                     if cacheFaultReturnP = nil then
  298.                         oe := memFullErr
  299.                     else begin
  300.                         cacheFaultReturnP^.done := 0;
  301.                         oe := TCPStrToAddr(dnrptr, hostName, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  302.                         if oe = cacheFault then begin
  303.                             timeout := TickCount + TO_FindAddress;
  304.                             oe := noErr;
  305.                         end
  306.                         else begin
  307.                             cacheFaultReturnP^.done := -1;
  308.                             cacheFaultReturnP^.hi.rtnCode := oe;
  309.                         end;
  310.                         status := CS_Searching;
  311.                     end;
  312.                     if oe <> noErr then begin
  313.                         if cacheFaultReturnP <> nil then
  314.                             DisposPtr(ptr(cacheFaultReturnP));
  315.                         DestroyConnection(cp);
  316.                     end;
  317.                 end;
  318.             end;
  319.         end;
  320.         FindAddress := oe;
  321.     end;
  322.  
  323.     procedure FindString (hostIP: longInt; var s: str255);
  324.     begin
  325.         TCPAddrToStr(dnrptr, hostIP, s);
  326.     end;
  327.  
  328.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  329.         var
  330.             oe: OSErr;
  331.             cpi: connectionIndex;
  332.     begin
  333.         oe := CreateConnection(cp, dataptr);
  334.         if oe = noErr then begin
  335.             cpi := cp;
  336.             if ValidConnection(cpi) then begin
  337.                 with connections[cpi] do begin
  338.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  339.                     if cacheFaultReturnP = nil then
  340.                         oe := memFullErr
  341.                     else begin
  342.                         cacheFaultReturnP^.done := 0;
  343.                         oe := TCPAddrToName(dnrptr, hostIP, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  344.                         if oe = cacheFault then begin
  345.                             timeout := TickCount + TO_FindName;
  346.                             oe := noErr;
  347.                         end
  348.                         else begin
  349.                             cacheFaultReturnP^.done := -1;
  350.                             cacheFaultReturnP^.hi.rtnCode := oe;
  351.                         end;
  352.                         status := CS_NameSearching;
  353.                     end;
  354.                     if oe <> noErr then begin
  355.                         if cacheFaultReturnP <> nil then
  356.                             DisposPtr(ptr(cacheFaultReturnP));
  357.                         DestroyConnection(cp);
  358.                     end;
  359.                 end;
  360.             end;
  361.         end;
  362.         FindName := oe;
  363.     end;
  364.  
  365.     function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  366.         var
  367.             oe: OSErr;
  368.             cpi: connectionIndex;
  369.     begin
  370.         oe := CreateConnection(cp, dataptr);
  371.         cpi := cp;
  372.         if ValidConnection(cpi) then
  373.             with connections[cpi] do begin
  374.                 oe := TCPPassiveOpen(tcpc, buffersize, localPort, remotehost, remoteport, nil);
  375.                 timeout := TickCount + TO_PassiveOpen;
  376.                 status := CS_Opening;
  377.                 if oe <> noErr then
  378.                     DestroyConnection(cp);
  379.             end;
  380.         NewPassiveConnection := oe;
  381.     end;
  382.  
  383.     function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  384.         var
  385.             oe: OSErr;
  386.             cpi: connectionIndex;
  387.     begin
  388.         oe := CreateConnection(cp, dataptr);
  389.         cpi := cp;
  390.         if ValidConnection(cpi) then
  391.             with connections[cpi] do begin
  392.                 oe := TCPActiveOpen(tcpc, buffersize, 0, remotehost, remoteport, nil);
  393.                 timeout := TickCount + TO_ActiveOpen;
  394.                 status := CS_Opening;
  395.                 if oe <> noErr then
  396.                     DestroyConnection(cp);
  397.             end;
  398.         NewActiveConnection := oe;
  399.     end;
  400.  
  401.     procedure CloseConnection (cp: connectionIndex);
  402.         var
  403.             oe: OSErr;
  404.     begin
  405.         if ValidConnection(cp) then
  406.             with connections[cp] do begin
  407.                 if not closedone then begin
  408.                     if MyTCPState(tcpc) <> T_Closed then
  409.                         oe := TCPClose(tcpc, nil);
  410.                     closedone := true;
  411.                 end;
  412.                 status := CS_Closing;
  413.             end;
  414.     end;
  415.  
  416.     procedure AbortConnection (cp: connectionIndex);
  417.         var
  418.             oe: OSErr;
  419.     begin
  420.         if ValidConnection(cp) then
  421.             with connections[cp] do begin
  422.                 if MyTCPState(tcpc) <> T_Closed then
  423.                     oe := TCPAbort(tcpc);
  424.                 status := CS_Closing;
  425.             end;
  426.     end;
  427.  
  428.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  429.         procedure HandleConnection (cp: connectionIndex);
  430.             var
  431.                 oe: OSErr;
  432.                 dummysp: stringPtr;
  433.                 l: integer;
  434.                 rcp: connectionIndex;
  435.         begin
  436.             if (cp < 1) or (cp > max_connections) then
  437.                 DebugStr('GetConnectionEvent:Invalid Connection Index');
  438.             if connections[cp].magic <> TCPCMagic then
  439.                 DebugStr('GetConnectionEvent:Bad TCPCMagic number');
  440.             with connections[cp] do begin
  441.                 rcp := conmagic;
  442.                 cer.connection := rcp;
  443.                 cer.tcpc := tcpc;
  444.                 cer.dataptr := dataptr;
  445.                 cer.timedout := false;
  446.                 case status of
  447.                     CS_NameSearching: 
  448.                         with cacheFaultReturnP^, hi do begin
  449.                             if done <> 0 then begin
  450.                                 if rtnCode = noErr then begin
  451.                                     cer.event := C_NameFound;
  452.                                     SanitizeHostName(rtnHostName);
  453.                                     stringHandle(cer.value) := NewString(rtnHostName);
  454.                                 end
  455.                                 else begin
  456.                                     cer.event := C_NameSearchFailed;
  457.                                     cer.value := rtnCode;
  458.                                 end
  459.                             end
  460.                             else if TickCount > timeout then begin
  461.                                 cer.event := C_NameSearchFailed;
  462.                                 cer.value := 1;
  463.                                 cer.timedout := true;
  464.                             end;
  465.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  466.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  467.                                     DisposPtr(ptr(cacheFaultReturnP));
  468.                                 cacheFaultReturnP := nil;
  469.                                 DestroyConnection(rcp);
  470.                             end; {if}
  471.                         end; {with}
  472.                     CS_Searching: 
  473.                         with cacheFaultReturnP^, hi do begin
  474.                             if rtnCode = noErr then begin
  475.                                 cer.event := C_Found;
  476.                                 cer.value := addrs[1];
  477.                             end
  478.                             else if done <> 0 then begin
  479.                                 cer.event := C_SearchFailed;
  480.                                 cer.value := rtnCode;
  481.                             end
  482.                             else if TickCount > timeout then begin
  483.                                 cer.event := C_SearchFailed;
  484.                                 cer.value := 1;
  485.                                 cer.timedout := true;
  486.                             end;
  487.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  488.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  489.                                     DisposPtr(ptr(cacheFaultReturnP));
  490.                                 cacheFaultReturnP := nil;
  491.                                 DestroyConnection(rcp);
  492.                             end; {if}
  493.                         end; {with}
  494.                     CS_Opening: 
  495.                         case MyTCPState(tcpc) of
  496.                             T_WaitingForOpen, T_Opening, T_Listening: 
  497.                                 if TickCount > timeout then begin
  498.                                     CloseConnection(rcp);
  499.                                     cer.event := C_FailedToOpen;
  500.                                     cer.timedout := true;
  501.                                 end;
  502.                             T_Established:  begin
  503.                                 cer.event := C_Established;
  504.                                 status := CS_Established;
  505.                                 timeout := maxLongInt;
  506.                             end;
  507.                             T_PleaseClose, T_Closing:  begin
  508.                                 CloseConnection(rcp);
  509.                                 cer.value := 1;
  510.                                 cer.event := C_FailedToOpen;
  511.                                 timeout := TickCount + TO_Closing;
  512.                             end;
  513.                             T_Closed:  begin
  514.                                 status := CS_Closing;
  515.                                 cer.value := 2;
  516.                                 cer.event := C_FailedToOpen;
  517.                                 timeout := TickCount + TO_Closing;
  518.                             end;
  519.                             otherwise
  520.                                 ;
  521.                         end; {case }
  522.                     CS_Established: 
  523.                         case MyTCPState(tcpc) of
  524.                             T_WaitingForOpen, T_Opening, T_Listening: 
  525.                                 DebugStr('Strange State 1');
  526.                             T_Established:  begin
  527.                                 cer.value := TCPCharsAvailable(tcpc);
  528.                                 if cer.value > 0 then
  529.                                     cer.event := C_CharsAvailable;
  530.                             end;
  531.                             T_PleaseClose, T_Closing:  begin
  532.                                 cer.value := TCPCharsAvailable(tcpc);
  533.                                 if cer.value > 0 then
  534.                                     cer.event := C_CharsAvailable
  535.                                 else begin
  536. {    CloseConnection(rcp);}
  537.                                     status := CS_Closing;
  538.                                     cer.event := C_Closing;
  539.                                     timeout := TickCount + TO_Closing;
  540.                                 end;
  541.                             end;
  542.                             T_Closed:  begin
  543.                                 status := CS_Closing;
  544.                                 cer.event := C_Closing;
  545.                                 timeout := TickCount + TO_Closing;
  546.                             end;
  547.                             otherwise
  548.                                 ;
  549.                         end;
  550.                     CS_Closing: 
  551.                         case MyTCPState(tcpc) of
  552.                             T_WaitingForOpen, T_Opening, T_Listening: 
  553.                                 DebugStr('Strange State 2');
  554.                             T_PleaseClose, T_Closing, T_Established:  begin
  555.                                 cer.value := TCPCharsAvailable(tcpc);
  556.                                 if cer.value > 0 then
  557.                                     cer.event := C_CharsAvailable
  558.                                 else if TickCount > timeout then begin
  559.                                     cer.event := C_Closed;
  560.                                     if tcpc <> nil then
  561.                                         oe := TCPRelease(tcpc);
  562.                                     cer.timedout := true;
  563.                                     DestroyConnection(rcp);
  564.                                 end;
  565.                             end;
  566.                             T_Closed:  begin
  567.                                 cer.event := C_Closed;
  568.                                 if tcpc <> nil then
  569.                                     oe := TCPRelease(tcpc);
  570.                                 DestroyConnection(rcp);
  571.                             end;
  572.                             otherwise
  573.                                 ;
  574.                         end;
  575.                     otherwise
  576.                         ;
  577.                 end;
  578.  
  579.                 if (cer.event = C_NoEvent) & (TickCount > heartbeat) then begin
  580.                     cer.event := C_HeartBeat;
  581.                     heartbeat := TickCount + period;
  582.                 end;
  583.  
  584.             end;{with}
  585.         end;{HandleConnection}
  586.         var
  587.             oci: connectionIndex;
  588.     begin
  589.         cer.event := C_NoEvent;
  590.         if cp <> any_connection then begin
  591.             if ValidConnection(cp) then
  592.                 HandleConnection(cp);
  593.         end
  594.         else begin
  595.             oci := connectionItem;
  596.             repeat
  597.                 if connections[connectionItem].magic = TCPCMagic then begin
  598.                     HandleConnection(connectionItem);
  599.                     if cer.event <> C_NoEvent then
  600.                         leave;
  601.                 end;{if}
  602.                 if connectionItem = max_connections then
  603.                     connectionItem := 1
  604.                 else
  605.                     connectionItem := connectionItem + 1;
  606.             until oci = connectionItem;
  607.         end;{if}
  608.         GetConnectionEvent := cer.event <> C_NoEvent;
  609.     end;{GetConnectionEvent}
  610.  
  611. end.